import Axios, {
  type AxiosInstance,
  type AxiosRequestConfig,
  type CustomParamsSerializer
} from "axios";
import type {
  PureHttpError,
  RequestMethods,
  PureHttpResponse,
  PureHttpRequestConfig,
  ResData
} from "./types.d";

import { Page } from "./types.d";
import { stringify } from "qs";
import NProgress from "../progress";
import { getToken, formatToken } from "@/utils/auth";
import { useUserStoreHook } from "@/store/modules/user";
import { plainToInstance, type ClassConstructor } from "class-transformer";
import { onReset } from "@/layout/hooks/useDataThemeChange";
import { ElMessage } from "element-plus";
import "reflect-metadata";

// 相关配置请参考：www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
  // 请求超时时间
  timeout: 10000,
  baseURL: import.meta.env.VITE_API_BASE_URL,
  headers: {
    Accept: "application/json, text/plain, */*",
    "Content-Type": "application/json",
    "X-Requested-With": "XMLHttpRequest"
  },
  // 数组格式参数序列化（https://github.com/axios/axios/issues/5142）
  paramsSerializer: {
    serialize: stringify as unknown as CustomParamsSerializer
  }
};

class PureHttp {
  constructor() {
    this.httpInterceptorsRequest();
    this.httpInterceptorsResponse();
  }

  /** `token`过期后，暂存待执行的请求 */
  private static requests = [];

  /** 防止重复刷新`token` */
  private static isRefreshing = false;

  /** 初始化配置对象 */
  private static initConfig: PureHttpRequestConfig = {};

  /** 保存当前`Axios`实例对象 */
  private static axiosInstance: AxiosInstance = Axios.create(defaultConfig);

  /** 重连原始请求 */
  private static retryOriginalRequest(config: PureHttpRequestConfig) {
    return new Promise(resolve => {
      PureHttp.requests.push((token: string) => {
        config.headers["Token"] = formatToken(token);
        resolve(config);
      });
    });
  }

  /** 请求拦截 */
  private httpInterceptorsRequest(): void {
    PureHttp.axiosInstance.interceptors.request.use(
      async (config: PureHttpRequestConfig): Promise<any> => {
        // 开启进度条动画
        NProgress.start();

        // 定义递归函数处理参数中的字符串
        const trimStringValues = (obj: any) => {
          if (typeof obj === "string") {
            return obj.trim();
          } else if (Array.isArray(obj)) {
            return obj.map(item => trimStringValues(item));
          } else if (typeof obj === "object" && obj !== null) {
            const newObj: Record<string, any> = {};
            for (const key in obj) {
              if (obj.hasOwnProperty(key)) {
                newObj[key] = trimStringValues(obj[key]);
              }
            }
            return newObj;
          }
          return obj;
        };
        // 处理 params 和 data 中的字符串参数
        if (config.params) {
          config.params = trimStringValues(config.params);
        }
        if (config.data) {
          config.data = trimStringValues(config.data);
        }
        console.log("requestParams", config.data);
        // 优先判断post/get等方法是否传入回调，否则执行初始化设置等回调
        if (typeof config.beforeRequestCallback === "function") {
          config.beforeRequestCallback(config);
          return config;
        }
        if (PureHttp.initConfig.beforeRequestCallback) {
          PureHttp.initConfig.beforeRequestCallback(config);
          return config;
        }
        /** 请求白名单，放置一些不需要`token`的接口（通过设置请求白名单，防止`token`过期后再请求造成的死循环问题） */
        const whiteList = ["/login"];
        return whiteList.some(url => config.url.endsWith(url))
          ? config
          : new Promise(resolve => {
              const data = getToken();
              if (data) {
                config.headers["Token"] = formatToken(data.token);
                resolve(config);
              } else {
                resolve(config);
              }
            });
      },
      error => {
        return Promise.reject(error);
      }
    );
  }

  /** 响应拦截 */
  private httpInterceptorsResponse(): void {
    const instance = PureHttp.axiosInstance;
    instance.interceptors.response.use(
      (response: PureHttpResponse) => {
        const $config = response.config;
        // 关闭进度条动画
        NProgress.done();
        // 优先判断post/get等方法是否传入回调，否则执行初始化设置等回调
        if (typeof $config.beforeResponseCallback === "function") {
          $config.beforeResponseCallback(response);
          return response.data;
        }
        if (PureHttp.initConfig.beforeResponseCallback) {
          PureHttp.initConfig.beforeResponseCallback(response);
          return response.data;
        }
        return response.data;
      },
      (error: PureHttpError) => {
        const $error = error;
        $error.isCancelRequest = Axios.isCancel($error);
        // 关闭进度条动画
        NProgress.done();
        // 所有的响应异常 区分来源为取消请求/非取消请求
        return Promise.reject($error);
      }
    );
  }

  /** 通用请求工具函数 */
  public request<T>(
    method: RequestMethods,
    url: string,
    param?: AxiosRequestConfig,
    type?: ClassConstructor<any>,
    axiosConfig?: PureHttpRequestConfig
  ): Promise<ResData<T>> {
    const config = {
      method,
      url,
      ...param,
      ...axiosConfig
    } as PureHttpRequestConfig;

    // 单独处理自定义请求/响应回调
    return new Promise<ResData<T>>((resolve, reject) => {
      PureHttp.axiosInstance
        .request(config)
        .then(res => {
          const resData = res as unknown as ResData<T>;
          const code = resData.code;
          if (code === 0 && type) {
            if (Array.isArray(resData.data)) {
              resData.data = resData.data.map(item => {
                return plainToInstance(type, item);
              }) as T;
            } else {
              // resData.data = plainToInstance(type, resData.data) as T
              const page = (resData.data as any)?.page;
              if (page && typeof page === "number" && page > 0) {
                const page = plainToInstance(Page, resData.data);
                page.items = page.items.map(item => {
                  return plainToInstance(type, item);
                });
                resData.data = page as T;
              } else {
                resData.data = plainToInstance(type, resData.data) as T;
              }
            }
          }
          console.log("res", res, code);
          if (code === 0) {
            // 2.1 提取核心数据 res.data
            resolve(resData);
          } else if (code === 9998 || code === 9999) {
            onReset();
            // 401错误  -> 清理用户信息，跳转到登录页
            // const userStore = useUserStore();
            // userStore.clearUserInfo();
            // uni.reLaunch({ url: "/pages/Member/Login" });
            ElMessage.error(resData.message);
            reject(res);
          } else {
            // 其他错误 -> 根据后端错误信息轻提示
            // !options.hideErrorToast &&
            //   uni.showToast({
            //     icon: "none",
            //     title: (res.data as ResData<T>).message || "请求错误"
            //   });
            ElMessage.error(resData.message || "请求错误");
            reject(res);
          }
        })
        .catch(err => {
          console.log("err", err);
          reject(err);
        });
    });
  }

  /** 单独抽离的`post`工具函数 */
  public post<T, P>(
    url: string,
    params?: AxiosRequestConfig<P>,
    type?: ClassConstructor<any>,
    config?: PureHttpRequestConfig
  ) {
    return this.request<T>("post", url, params, type, config);
  }

  /** 单独抽离的`get`工具函数 */
  public get<T, P>(
    url: string,
    params?: AxiosRequestConfig<P>,
    type?: ClassConstructor<any>,
    config?: PureHttpRequestConfig
  ) {
    return this.request<T>("get", url, params, type, config);
  }

  /** 上传图片工具函数 */
  public uploadImage<T>(
    url: string,
    file: File,
    type?: ClassConstructor<any>,
    config?: PureHttpRequestConfig
  ) {
    const formData = new FormData();
    formData.append("file", file); // 'file' 是后端接收文件的字段名，根据实际情况调整

    const params = {
      data: formData,
      headers: {
        "Content-Type": "multipart/form-data"
      }
    };

    return this.request<T>("post", url, params, type, config);
  }
}

export const http = new PureHttp();
